#include <memory>
#include <unordered_map>
#include <fstream>
#include <signal.h>
#include "udpServer.hpp"
#include "onlineUser.hpp"
// 把用户管理模块包进来

using namespace Server;

const char *dictTxt = "./dict.txt";

static void Usage(string proc)
{
    cout << "\nUsage:\n\t" << proc << " local_port\n\n";
}
static bool cutString(const string &target, string *s1, string *s2, string sep)
{
    //datagram:数据报
    auto pos = target.find(sep);
    if(pos == string::npos)
    {
        return false;
    }
    *s1 = target.substr(0, pos); // 截取[)的区间
    *s2 = target.substr(pos + sep.size()); // 截取[)的区间,后面参数不传默认截取到末尾
    return true;
}
static unordered_map<string, string> dict;
static void initdict()
{
    ifstream in(dictTxt, ios::binary);
    if(!in.is_open())
    {
        cerr << "open file" << dictTxt << " error" << endl;
        exit(OPEN_ERR);
    }
    string line;
    string key, value;
    while(getline(in, line))//发生隐式类型转换
    {
        // cout << line << endl;//测试代码
        if(cutString(line, &key, &value, ":"))
        {
            dict.insert(make_pair(key, value));
        }
    }

    cout << "load dict success!" << endl;
}
void reload (int signo)//热加载
{
    (void)signo;
    initdict();
}
static void debugPrint()
{
    for(auto &dt : dict)
    {
        cout << dt.first << " -> " << dt.second << endl;
    }
}

// demo1 -- 翻译
void translateMessage(int sockfd, string clientip, uint16_t clientport, string message)
{
    //对message进行特定的业务处理,而不关心message怎么来的 -----server通信和业务逻辑的解耦!!!
    
    // ---婴儿版的业务逻辑
    string response_message;
    auto iter = dict.find(message);
    if(iter == dict.end()) 
    {
        response_message = "unknown";
    }
    else
    {
        response_message = iter->second;
    }

    // 服务器将消息发回客户端,需要有client的sockaddr_in
    struct sockaddr_in client;
    bzero(&client, sizeof(client));
    client.sin_addr.s_addr = inet_addr(clientip.c_str());
    client.sin_family = AF_INET;
    client.sin_port = htons(clientport);
    
    sendto(sockfd, response_message.c_str(), response_message.size(), 0, (struct sockaddr *)&client, sizeof(client));
}
// demo2 -- 命令执行
void execCommand(int sockfd, string clientip, uint16_t clientport, string cmd)
{
    if(cmd.find("rm") != string::npos || cmd.find("mv") != string::npos || cmd.find("rmdir") != string::npos)
    {
        cerr << clientip << "[" << clientport << "]" << "# 正在做一个非法的操作: " << cmd << endl;
        return;
    }
    
    //1. cmd解析, ls -a -l
    //2. 如果必要，可能需要fork+exec*
    string response;
    FILE* fp = popen(cmd.c_str(), "r");
    if(fp == nullptr)
    {
        response = cmd + " exec failed";
    }
    char line[1024];
    while(fgets(line, sizeof(line) - 1, fp))
    {
        response += line;
    }

    // 服务器将消息发回客户端,需要有client的sockaddr_in
    struct sockaddr_in client;
    bzero(&client, sizeof(client));
    client.sin_addr.s_addr = inet_addr(clientip.c_str());
    client.sin_family = AF_INET;
    client.sin_port = htons(clientport);
    
    sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&client, sizeof(client));
    pclose(fp);
}
// demo3 -- 群聊
static OnlineUser onlineuser;
void routeMessage(int sockfd, string clientip, uint16_t clientport, string message)//把消息路由给所有人
{
    if(message == "online")
        onlineuser.addUser(clientip, clientport);
    if(message == "offline")
        onlineuser.delUser(clientip, clientport);
        
    // 用户在线才可以进行消息转发
    if(onlineuser.isOnline(clientip, clientport))
    {
        // 消息的路由群发
        onlineuser.broadcastMessage(sockfd, clientip, clientport, message);
    }
    else
    {
        struct sockaddr_in client;
        bzero(&client, sizeof(client));
        client.sin_addr.s_addr = inet_addr(clientip.c_str());
        client.sin_family = AF_INET;
        client.sin_port = htons(clientport);

        string response = "你还没有上线, 请先上线, 运行->online";
        sendto(sockfd, response.c_str(), response.size(), 0, (struct sockaddr *)&client, sizeof(client));        
    }
}
// demo4 -- win转发
void winforwardMessage(int sockfd, string clientip, uint16_t clientport, string message)
{
    string response_message = message + "(server echo)";


    // 服务器将消息发回客户端,需要有client的ip+port
    struct sockaddr_in client;
    bzero(&client, sizeof(client));
    client.sin_addr.s_addr = inet_addr(clientip.c_str());
    client.sin_family = AF_INET;
    client.sin_port = htons(clientport);
    
    sendto(sockfd, response_message.c_str(), response_message.size(), 0, (struct sockaddr *)&client, sizeof(client));
}

// Usage-> ./udpServer  port
int main(int argc, char *argv[])
{
    if(argc != 2)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }
    // string ip = argv[1];
    uint16_t port = atoi(argv[1]); // int->short int发送截断

    // signal(2, reload);//注册一个信号捕捉函数, 用于支持热加载
    // initdict();
    // debugPrint();

    
    unique_ptr<udpServer> usvr(new udpServer(translateMessage, port));
    // unique_ptr<udpServer> usvr(new udpServer(execCommand, port));
    // unique_ptr<udpServer> usvr(new udpServer(routeMessage, port));
    // unique_ptr<udpServer> usvr(new udpServer(winforwardMessage, port));

    usvr->initServer();
    usvr->start();

    return 0;
}
